package com.hb.core.base;

import cn.hutool.core.util.ReflectUtil;
import com.hb.core.annotation.AllowOrderField;
import com.hb.core.constant.Constants;
import lombok.Data;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @description: 查询条件基础类
 * @projectName: zhb-frame-build
 * @author: zhouhaizhi
 * @createTime: 2021/8/16 11:33
 * @version:1.0
 */
@Data
public abstract class BaseCondition {

    /*
        排序字段
        eg：orderByField = field1,field2 asc;field3 desc
     */
    private String orderByField;

    private static final String ORDER_BY_FIELD_SEPARATOR = ",";

    private static final String EMPTY = "";

    /**
     *@描述  返回允许用于排序的数据库字段名集合
     *@创建人 zhouhaizhi
     *@创建时间 2021/8/16 14:35
     *@参数 
     *@返回值 
     *@修改人和其它信息
     */
    protected Set<String> listAllowOrderByField() {
        Class<?> clazz = this.getClass();
        if (!AllowOrderFieldCache.containClass(clazz.getSimpleName())) {
            //允许不同子类间同步，不允许同一种子类互相同步
            synchronized (AllowOrderFieldCache.class) {
                Field[] fields = ReflectUtil.getFields(this.getClass());
                Set<Field> allowOrderFieldSet = Arrays.stream(fields)
                        .filter(i -> 0 != i.getAnnotationsByType(AllowOrderField.class).length)
                        .collect(Collectors.toSet());
                Set<String> fieldSet = new HashSet<>(allowOrderFieldSet.size());
                for (Field field : allowOrderFieldSet) {
                    AllowOrderField annotation = field.getAnnotationsByType(AllowOrderField.class)[0];
                    if (StringUtils.isNotBlank(annotation.value())) {
                        fieldSet.add(annotation.value());
                    } else {
                        fieldSet.add(StringUtils.toRootUpperCase(field.getName()));
                    }
                }
                AllowOrderFieldCache.setCacheOnClass(clazz, fieldSet);
            }
        }
        return null;
    }

    /**
     *@描述  获取排序字段集合
     *@创建人 zhouhaizhi
     *@创建时间 2021/8/16 14:34
     *@参数 
     *@返回值 
     *@修改人和其它信息
     */
    public List<OrderField> getOrderByFieldList() {
        Set<String> allowOrderByField = this.listAllowOrderByField();
        if (CollectionUtils.isEmpty(allowOrderByField) || StringUtils.isBlank(orderByField)) {
            return Collections.emptyList();
        }
        List<String> targetOrderByFields = Arrays.stream(orderByField.split(ORDER_BY_FIELD_SEPARATOR))
                .map(String::trim)
                .collect(Collectors.toList());
        List<OrderField> orderFieldList = new ArrayList<>();
        String field = null;
        String sort = null;
        final String sqlErrorMessage = "使用了违规的排序字段";
        for (String orderField : targetOrderByFields) {
            int lastIndexOfEmpty = orderField.lastIndexOf(EMPTY);
            if (lastIndexOfEmpty > 0) {
                field = orderField.substring(0, lastIndexOfEmpty).trim();
                sort = orderField.substring(lastIndexOfEmpty).trim().toUpperCase();
            } else {
                field = orderField.trim();
            }
            if (StringUtils.isBlank(sort)) {
                sort = Constants.SORT_ASC;
            } else if (!Constants.SORT_ASC.equals(sort) && !Constants.SORT_DESC.equals(sort)) {
                throw new RuntimeException("使用了违规排序方式");
            }
            if (!allowOrderByField.contains(field)) {
                throw new RuntimeException(sqlErrorMessage);
            }
            orderFieldList.add(new OrderField(field, sort));
            field = null;
            sort = null;
        }

        return orderFieldList;
    }

    /**
     *@描述  拼装排序部分的语句    
     *@创建人 zhouhaizhi
     *@创建时间 2021/8/16 14:34
     *@参数 
     *@返回值 
     *@修改人和其它信息
     */
    public String concatOrderBy() {
        List<OrderField> orderFields = this.getOrderByFieldList();
        if (CollectionUtils.isNotEmpty(orderFields)) {
            final StringJoiner sj = new StringJoiner(ORDER_BY_FIELD_SEPARATOR, " order by ", " ");
            for (OrderField orderField : orderFields) {
                sj.add(orderField.toString());
            }
            return sj.toString();
        }
        return StringUtils.EMPTY;
    }

}
